package com.cndw.kungfu.model.pvp.campcross;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

import com.cndw.kungfu.config.Constants;
import com.cndw.kungfu.ext.LangConfigLib;
import com.cndw.kungfu.ext.LogUtil;
import com.cndw.kungfu.ext.NumberProcesser;
import com.cndw.kungfu.model.Context;
import com.cndw.kungfu.model.DataSerialize;
import com.cndw.kungfu.model.activity.domain.CrossServer;
import com.cndw.kungfu.model.battle.Battle;
import com.cndw.kungfu.model.pvp.api.ApiCore;
import com.cndw.kungfu.model.pvp.api.CampApiClient;
import com.cndw.kungfu.model.pvp.war.WarFighter;

public class CampCrossArea {

	private ConcurrentHashMap<Long, CampTeam> joinTeams = new ConcurrentHashMap<Long, CampTeam>();

	private ConcurrentHashMap<Long, Long> uidMasterIds = new ConcurrentHashMap<Long, Long>();

	private LinkedList<CampCrossLog> logs = new LinkedList<CampCrossLog>();

	private List<Object> topPlayers = new ArrayList<Object>();

	private List<Object> orderList = new ArrayList<Object>();

	private int area;

	private int nameIndexLeft = 0;
	private int nameIndexRight = 0;

	private ScheduledFuture<?> vsTask;

	private boolean open;

	private static ConcurrentHashMap<Integer, CampCrossArea> instanceMap = new ConcurrentHashMap<Integer, CampCrossArea>();

	private CampCrossArea(int area) {
		this.area = area;
	}

	private static CampCrossArea getInstance(int area) {
		if (!instanceMap.containsKey(area)) {
			instanceMap.putIfAbsent(area, new CampCrossArea(area));
		}
		return instanceMap.get(area);
	}

	public static CampCrossArea getBySid(int sid) {
		return getByArea(CrossServer.getArea(sid, 1));
	}

	public static CampCrossArea getByArea(int area) {
		return getInstance(area);
	}

	public long havedJoin(long[] ids) {
		for (Long uid : ids) {
			if (uidMasterIds.containsKey(uid)) {
				return uid;
			}
		}
		return 0;
	}

	public void join(CampTeam campTeam) {
		joinTeams.put(campTeam.getMasterId(), campTeam);
		for (Long uid : campTeam.getUids()) {
			uidMasterIds.put(uid, campTeam.getMasterId());
		}
	}

	public int getNameIndexLeft() {
		return nameIndexLeft;
	}

	public void setNameIndexLeft(int nameIndexLeft) {
		this.nameIndexLeft = nameIndexLeft;
	}

	public int getNameIndexRight() {
		return nameIndexRight;
	}

	public void setNameIndexRight(int nameIndexRight) {
		this.nameIndexRight = nameIndexRight;
	}

	public boolean isJoin(long uid) {
		return uidMasterIds.containsKey(uid);
	}

	public long getMasterId(long uid) {
		if (uidMasterIds.containsKey(uid)) {
			return uidMasterIds.get(uid);
		}
		return 0;
	}

	public synchronized void start() {
		if (!ApiCore.isCrossServer()) {
			return;
		}
		if (open) {
			return;
		}
		if (vsTask != null) {
			vsTask.cancel(false);
		}

		CampApiClient.state(area, true);

		int maxName = LangConfigLib.getConfigs("config.campcross.read").length;
		nameIndexLeft = NumberProcesser.mtRand(maxName) - 1;
		nameIndexRight = NumberProcesser.mtRand(maxName) - 1;
		open = true;
		autoJoin();

		LogUtil.getMain().debug("camp cross start with joinTeams  " + joinTeams.size());

		readyVS();

		LogUtil.getMain().debug("camp cross is ok.... ");
		CampCrossScoreComparator comparator = new CampCrossScoreComparator();
		TreeSet<CampTeam> treeSet = new TreeSet<CampTeam>(comparator);
		treeSet.addAll(joinTeams.values());
		boolean source = true;
		for (CampTeam campTeam : treeSet) {
			source = !source;
			campTeam.setSource(source);
		}
		CampCrossEvent crossEvent = new CampCrossEvent(area);
		vsTask = Context.getTimerServer().scheduleAtFixedRate(crossEvent, 30, 30);

	}

	public synchronized void autoJoin() {
		if (area > 0) {
			return;
		}
		int joinSize = 1000;

		List<Long> heroList = DataSerialize.getInstance().getChallengeData().getPlayers(1, joinSize);

		LinkedList<Long> ids = new LinkedList<Long>();
		for (Long targetId : heroList) {
			if (uidMasterIds.containsKey(targetId)) {
				continue;
			}
			ids.add(targetId);
			if (ids.size() == 3) {
				CampTeam campTeam = new CampTeam(ids);
				join(campTeam);
				ids.clear();
			}
		}
	}

	private synchronized void readyVS() {
		boolean err = false;
		for (CampTeam e : joinTeams.values()) {
			if (e.getPower() == 0) {
				try {
					Collection<WarFighter> fighters = CampApiClient.getFighters(e.getSid(), e.getIds());
					if (fighters != null) {
						e.updateFighter(fighters);
					} else {
						err = true;
						LogUtil.getMain().error("camp cross get err " + e.getSid() + " : " + e.getIds());
					}
				} catch (Exception e2) {
					err = true;
					e2.printStackTrace();
				}

			}
		}
		if (err) {
			readyVS();
			LogUtil.getMain().error("camp cross ready err ...");
		}
	}

	public synchronized void stop() {
		if (vsTask != null) {
			vsTask.cancel(false);
		}
		open = false;

		clacOrderOnEnd();

		joinTeams.clear();
		uidMasterIds.clear();
		logs.clear();
		

		CampApiClient.state(area, false);
	}

	public synchronized void vs() {
		if (!open) {
			return;
		}
		// LogUtil.getMain().debug("vs ....");
		List<Long> sourceIds = new ArrayList<Long>();
		List<Long> targetIds = new ArrayList<Long>();

		for (CampTeam e : joinTeams.values()) {
			if (e.isSource()) {
				sourceIds.add(e.getMasterId());
			} else {
				targetIds.add(e.getMasterId());
			}
		}
		Collections.shuffle(sourceIds);
		Collections.shuffle(targetIds);
		List<CampCrossLog> currentLogs = new ArrayList<CampCrossLog>();
		int maxSize = Math.max(sourceIds.size(), targetIds.size());
		for (int j = 0; j < maxSize; j++) {

			try {
				boolean npcSource = false, npcTarget = false;
				if (sourceIds.size() <= j) {
					npcSource = true;
				}
				if (targetIds.size() <= j) {
					npcTarget = true;
				}
				if (npcSource && npcTarget) {
					continue;
				}
				
				CampTeam sourceCamp = npcSource ? new CampTeamNpc(true) : joinTeams.get(sourceIds.get(j));
				CampTeam targetCamp = npcTarget ? new CampTeamNpc(false) : joinTeams.get(targetIds.get(j));
				if (sourceCamp == null || targetCamp == null) {
					continue;
				}
				CampCrossLog record = oneBattle(sourceCamp, targetCamp);
				if (record == null) {
					continue;
				}
				currentLogs.add(record);

			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		logs.addAll(currentLogs);

		clacOrderList();

		CampCrossReport report = new CampCrossReport();
		report.setLogs(currentLogs);
		report.setTop3(topPlayers);

		CampApiClient.sendRecords(area, report);

	}

	private synchronized void clacOrderList() {
		CampCrossWinComparator comparator = new CampCrossWinComparator();
		TreeSet<CampTeam> treeSet = new TreeSet<CampTeam>(comparator);
		treeSet.addAll(joinTeams.values());
		List<Object> currentOrders = new ArrayList<Object>();
		for (int i = 0; i < 50; i++) {
			CampTeam e = treeSet.pollFirst();
			if (e != null) {
				currentOrders.add(new Object[] { e.getSid(), e.getMasterId(), e.getMasterName(), e.isSource(), e.getStreak(), e.getWin(), e.getAll() });
			}
		}
		orderList = currentOrders;
		if (currentOrders.size() > 3) {
			topPlayers = currentOrders.subList(0, 3);
		}else {
			topPlayers = currentOrders;
		}
	}

	private synchronized void clacOrderOnEnd() {
		CampCrossWinComparator comparator = new CampCrossWinComparator();
		TreeSet<CampTeam> treeSet = new TreeSet<CampTeam>(comparator);
		treeSet.addAll(joinTeams.values());
		for (int i = 0; i < 10; i++) {
			CampTeam e = treeSet.pollFirst();
			if (e != null) {
				CampApiClient.sendAward(e.getSid(), e.getIds(), i + 1);
			}
		}
	}

	private CampCrossLog oneBattle(CampTeam sourceCamp, CampTeam targetCamp) {

		if (sourceCamp == null || sourceCamp == null) {
			LogUtil.getMain().error("err null");
			return null;
		}
		sourceCamp.reset();
		targetCamp.reset();
		if (sourceCamp.getBattleMembers().size() == 0 || targetCamp.getBattleMembers().size() == 0) {
			LogUtil.getMain().error("err null");
			return null;
		}

		Battle battle = new Battle(sourceCamp, targetCamp);
		battle.execBattle(Constants.battle_pvpCross);
		battle.clear();

		CampTeam winCamp = battle.getWiner() == 1 ? sourceCamp : targetCamp;
		CampTeam losCamp = battle.getWiner() == 1 ? targetCamp : sourceCamp;

		winCamp.notifyWin(true);
		losCamp.notifyWin(false);

		CampCrossLog campCrossLog = new CampCrossLog();
		campCrossLog.setWinId(winCamp.getMasterId());
		campCrossLog.setWinName(winCamp.getMasterName());
		campCrossLog.setWinSid(winCamp.getSid());

		campCrossLog.setWinSource(winCamp.isSource());
		campCrossLog.setWinStreak(winCamp.getStreak());

		campCrossLog.setLossId(losCamp.getMasterId());
		campCrossLog.setLossName(losCamp.getMasterName());
		campCrossLog.setLossSid(losCamp.getSid());

		int[] award = new int[4];
		award[0] = winCamp.getLevel() * 600 + winCamp.getStreak() * winCamp.getLevel() * 60;
		award[1] = winCamp.getLevel() * 50 + winCamp.getStreak() * winCamp.getLevel() * 5;
		award[2] = losCamp.getLevel() * 600;
		award[3] = losCamp.getLevel() * 50;

		campCrossLog.setAward(award);

		CampCrossReportBattle reportBattle = new CampCrossReportBattle();
		reportBattle.setBattleReport(battle.getBattleReport());

		reportBattle.setUids(winCamp.getUids());
		reportBattle.setAward(new int[] { award[0], award[1] });
		reportBattle.setWin(true);
		
		CampApiClient.sendBattle(winCamp.getSid(), reportBattle);

		reportBattle.setUids(losCamp.getUids());
		reportBattle.setAward(new int[] { award[2], award[3] });
		reportBattle.setWin(false);

		CampApiClient.sendBattle(losCamp.getSid(), reportBattle);

		return campCrossLog;
	}

	public Collection<CampCrossLog> recordsView(int limit) {
		if (logs == null) {
			return null;
		}
		int size = logs.size();
		if (limit == 0 || limit >= size) {
			return new ArrayList<CampCrossLog>(logs);
		}
		return new ArrayList<CampCrossLog>(logs.subList(size - limit, size));
	}

	public Collection<CampCrossLog> recordsView(long uid, int limit) {
		ArrayList<CampCrossLog> cList = new ArrayList<CampCrossLog>();

		Iterator<CampCrossLog> it = logs.descendingIterator();
		int i = 0;
		while (it.hasNext()) {
			CampCrossLog campWarLog = (CampCrossLog) it.next();
			if (campWarLog != null) {
				if (campWarLog.getWinId() != uid && campWarLog.getLossId() != uid) {
					continue;
				}
				cList.add(campWarLog);
				i++;
				if (i >= limit) {
					break;
				}
			}
		}
		return cList;
	}

	public Object getOrders() {
		return orderList;
	}

	public Object getAllPlayers() {
		List<Object[]> allList = new ArrayList<Object[]>();
		for (CampTeam campTeam : joinTeams.values()) {
			allList.add(campTeam.getObj());
		}
		return allList;
	}

	public Object getTop3() {
		return topPlayers;
	}

	public CampTeam getCampTeam(long masterId) {
		long uid = uidMasterIds.containsKey(masterId) ? uidMasterIds.get(masterId) : masterId;
		return joinTeams.get(uid);
	}

	public Collection<CampTeam> getTeams() {
		return joinTeams.values();
	}

	public boolean isOpen() {
		return open;
	}

	
}
